import os  # 导入os模块用于操作文件和目录
from colorama import init, Fore, Style  # 导入colorama模块用于改变控制台输出的颜色

init()  # 初始化colorama模块

SIZE = 10  # 设置常量SIZE为10，表示储存药品信息的列表med的长度为10
med = [{'num1': 0, 'num2': 0, 'num3': 0, 'name': '', 'price1': 0.0, 'price2': 0.0} for _ in range(SIZE)]  # 创建一个包含10个字典的列表，用于储存药品信息

def display_title(title):  # 定义display_title函数，用于展示标题
    print(Fore.CYAN + Style.BRIGHT + f"\n{title.center(50, '*')}" + Style.RESET_ALL)  # 打印标题，并设置字体为亮蓝色

def display_menu():  # 定义display_menu函数，用于展示菜单选项
    print(Fore.YELLOW + Style.BRIGHT)  # 设置字体为亮黄色
    print("某医药公司售货系统".center(50, '*'))  # 打印系统名称，居中显示，使用*作为边界
    print("1: 录入药品信息".center(50))  # 打印菜单选项1，居中显示
    print("2: 顾客买药处理".center(50))  # 打印菜单选项2，居中显示
    print("3: 查看药品信息".center(50))  # 打印菜单选项3，居中显示
    print("4: 购进药品".center(50))  # 打印菜单选项4，居中显示
    print("5: 修改药品信息".center(50))  # 打印菜单选项5，居中显示
    print("6: 删除药品信息".center(50))  # 打印菜单选项6，居中显示
    print("7: 计算利润".center(50))  # 打印菜单选项7，居中显示
    print("8: 查看交易记录".center(50))  # 打印菜单选项8，居中显示
    print("9: 生成报告".center(50))  # 打印菜单选项9，居中显示
    print("10: 退出".center(50))  # 打印菜单选项10，居中显示
    print("请选择序号并按回车确认".center(50))  # 提示用户选择序号
    print(Style.RESET_ALL)  # 重置字体样式

def save():  # 定义save函数，用于保存药品信息到文件
    display_title("录入药品信息")  # 调用display_title函数，打印标题"录入药品信息"
    i = int(input("您要输入几种药品信息："))  # 提示用户输入药品的种类数量，并将输入转换为整数类型

    for j in range(i):  # 循环i次，根据用户输入的药品种类数量录入药品信息
        med[j]['num1'] = int(input("请输入药品的编号："))  # 提示用户输入药品编号，并将输入转换为整数类型，将结果赋值给med[j]['num1']
        med[j]['name'] = input("输入要添加的药品名称：")  # 提示用户输入药品名称，并将结果赋值给med[j]['name']
        med[j]['num2'] = int(input("购进数量："))  # 提示用户输入购进数量，并将输入转换为整数类型，将结果赋值给med[j]['num2']
        med[j]['price1'] = float(input("购进价格："))  # 提示用户输入购进价格，并将结果转换为浮点数类型，将结果赋值给med[j]['price1']
        med[j]['num3'] = int(input("出售药品数："))  # 提示用户输入出售药品数，并将结果转换为整数类型，将结果赋值给med[j]['num3']
        med[j]['price2'] = float(input("出售价格："))  # 提示用户输入出售价格，并将结果转换为浮点数类型，将结果赋值给med[j]['price2']
        print(f"{med[j]['name']} {med[j]['num2']} {med[j]['price1']} {med[j]['num3']} {med[j]['price2']}")  # 打印录入的药品信息

    with open("d:\\MyFile.txt", "w") as fp:  # 打开文件MyFile.txt，以写入模式
        fp.write("药品编号 药品名称 购进数量 购进价格 出售药品数 出售价格\n")  # 写入文件第一行为药品信息的标题
        for z in range(SIZE):  # 循环SIZE次，遍历药品列表med
            if med[z]['num1'] != 0:  # 如果药品编号不为0，则说明该药品有信息
                fp.write(
                    f"{med[z]['num1']} {med[z]['name']} {med[z]['num2']} {med[z]['price1']} {med[z]['num3']} {med[z]['price2']}\n")  # 将药品信息写入文件
    print(Fore.GREEN + "药品信息保存成功！" + Style.RESET_ALL)  # 打印保存成功的提示信息，并设置字体为亮绿色

def goujin():  # 定义goujin函数，用于购进药品
    display_title("购进药品")  # 调用display_title函数，打印标题"购进药品"
    num = int(input("输入药品编号："))  # 提示用户输入药品编号，并将输入转换为整数类型
    j = int(input("输入购进数量："))  # 提示用户输入购进数量，并将输入转换为整数类型

    for i in range(SIZE):  # 循环SIZE次，遍历药品列表med
        if num == med[i]['num1']:  # 如果药品编号与输入的药品编号相等
            med[i]['num2'] += j  # 将购进数量加上j，更新购进数量
            print(Fore.GREEN + f"购进成功，当前库存：{med[i]['num2']}" + Style.RESET_ALL)  # 打印购进成功的提示信息，并设置字体为亮绿色
            log_transaction(num, j, '购进')  # 调用log_transaction函数，记录交易记录
            return  # 结束函数

    print(Fore.RED + "未找到该药品编号。" + Style.RESET_ALL)  # 打印未找到药品编号的提示信息，并设置字体为红色

def chushou():  # 定义chushou函数，用于出售药品
    display_title("出售药品")  # 调用display_title函数，打印标题"出售药品"
    num = int(input("请输入药品编号："))  # 提示用户输入药品编号，并将输入转换为整数类型

    for i in range(SIZE):  # 循环SIZE次，遍历药品列表med
        if num == med[i]['num1']:  # 如果药品编号与输入的药品编号相等
            if med[i]['num2'] > 0:  # 如果库存数量大于0
                med[i]['num2'] -= 1  # 将库存数量减1，更新库存数量
                med[i]['num3'] += 1  # 将出售药品数加1，更新出售药品数
                print(
                    f"药品编号：{med[i]['num1']} 名称：{med[i]['name']} 售价：{med[i]['price2']}")  # 打印出售的药品信息
                log_transaction(num, 1, '出售')  # 调用log_transaction函数，记录交易记录
                return  # 结束函数
            else:
                print(Fore.RED + "库存不足，无法出售。" + Style.RESET_ALL)  # 打印库存不足无法出售的提示信息，并设置字体为红色
                return  # 结束函数
    print(Fore.RED + "未找到该药品编号。" + Style.RESET_ALL)  # 打印未找到药品编号的提示信息，并设置字体为红色

def mednow():  # 定义mednow函数，用于查看药品信息
    display_title("查看药品信息")  # 调用display_title函数，打印标题"查看药品信息"
    total_stock = 0  # 初始化总库存为0

    with open("d:\\MyFile.txt", "r") as fp:  # 打开文件MyFile.txt，以只读模式
        fp.readline()  # 读取文件的第一行，跳过表头
        for j in range(SIZE):  # 循环SIZE次，遍历药品列表med
            line = fp.readline().strip().split()  # 读取文件的一行，去掉空格和换行符，并拆分成字符串列表
            if len(line) == 6:  # 如果拆分后的列表长度为6，说明该行为有效的药品信息行
                med[j]['num1'], med[j]['name'], med[j]['num2'], med[j]['price1'], med[j]['num3'], med[j][
                    'price2'] = int(line[0]), line[1], int(line[2]), float(line[3]), int(line[4]), float(line[5])  # 将读取到的药品信息赋值给对应的药品字典
                total_stock += med[j]['num2']  # 累加每个药品的库存数量到总库存

    print(Fore.CYAN + "药品编号 药品名称 购进数量 购进价格 出售药品数 出售价" + Style.RESET_ALL)  # 打印药品信息的标题
    for i in range(SIZE):  # 循环SIZE次，遍历药品列表med
        if med[i]['num1'] != 0:  # 如果药品编号不为0，说明该药品有信息
            print(
                f"{med[i]['num1']} {med[i]['name']} {med[i]['num2']} {med[i]['price1']} {med[i]['num3']} {med[i]['price2']}")  # 打印药品信息

    print(Fore.GREEN + f"当前总库存：{total_stock}" + Style.RESET_ALL)  # 打印当前总库存，并设置字体为亮绿色

def log_transaction(num, quantity, transaction_type):  # 定义log_transaction函数，用于记录交易记录
    with open("d:\\TransactionLog.txt", "a") as log:  # 打开文件TransactionLog.txt，以追加模式
        log.write(f"{num} {quantity} {transaction_type}\n")  # 写入交易记录

def modify_medicine():  # 定义modify_medicine函数，用于修改药品信息
    display_title("修改药品信息")  # 调用display_title函数，打印标题"修改药品信息"
    num = int(input("请输入要修改的药品编号："))  # 提示用户输入要修改的药品编号，并将输入转换为整数类型
    for i in range(SIZE):  # 循环SIZE次，遍历药品列表med
        if med[i]['num1'] == num:  # 如果药品编号与输入的药品编号相等
            med[i]['name'] = input(f"输入药品的新名称（当前：{med[i]['name']}）：")  # 提示用户输入新的药品名称，并将结果赋值给med[i]['name']
            med[i]['num2'] = int(input(f"输入药品的新购进数量（当前：{med[i]['num2']}）："))  # 提示用户输入新的购进数量，并将结果转换为整数类型，将结果赋值给med[i]['num2']
            med[i]['price1'] = float(input(f"输入药品的新购进价格（当前：{med[i]['price1']}）："))  # 提示用户输入新的购进价格，并将结果转换为浮点数类型，将结果赋值给med[i]['price1']
            med[i]['num3'] = int(input(f"输入药品的新出售药品数（当前：{med[i]['num3']}）："))  # 提示用户输入新的出售药品数，并将结果转换为整数类型，将结果赋值给med[i]['num3']
            med[i]['price2'] = float(input(f"输入药品的新出售价格（当前：{med[i]['price2']}）："))  # 提示用户输入新的出售价格，并将结果转换为浮点数类型，将结果赋值给med[i]['price2']
            print(Fore.GREEN + "药品信息修改成功。" + Style.RESET_ALL)  # 打印药品信息修改成功的提示信息，并设置字体为亮绿色
            return  # 结束函数
    print(Fore.RED + "未找到该药品编号。" + Style.RESET_ALL)  # 打印未找到药品编号的提示信息，并设置字体为红色

def delete_medicine():  # 定义delete_medicine函数，用于删除药品信息
    display_title("删除药品信息")  # 调用display_title函数，打印标题"删除药品信息"
    num = int(input("请输入要删除的药品编号："))  # 提示用户输入要删除的药品编号，并将输入转换为整数类型
    for i in range(SIZE):  # 循环SIZE次，遍历药品列表med
        if med[i]['num1'] == num:  # 如果药品编号与输入的药品编号相等
            med[i] = {'num1': 0, 'num2': 0, 'num3': 0, 'name': '', 'price1': 0.0, 'price2': 0.0}  # 将该药品信息重置为空字典
            print(Fore.GREEN + "药品信息删除成功。" + Style.RESET_ALL)  # 打印药品信息删除成功的提示信息，并设置字体为亮绿色
            return  # 结束函数
    print(Fore.RED + "未找到该药品编号。" + Style.RESET_ALL)  # 打印未找到药品编号的提示信息，并设置字体为红色

def calculate_profit():  # 定义calculate_profit函数，用于计算利润
    display_title("计算利润")  # 调用display_title函数，打印标题"计算利润"
    total_profit = 0  # 初始化总利润为0
    for i in range(SIZE):  # 循环SIZE次，遍历药品列表med
        if med[i]['num1'] != 0:  # 如果药品编号不为0，说明该药品有信息
            profit = (med[i]['price2'] - med[i]['price1']) * med[i]['num3']  # 计算药品的利润
            total_profit += profit  # 将药品的利润累加到总利润中
            print(f"药品编号：{med[i]['num1']} 名称：{med[i]['name']} 利润：{profit:.2f}")  # 打印药品的利润
    print(Fore.GREEN + f"总利润：{total_profit:.2f}" + Style.RESET_ALL)  # 打印总利润，并设置字体为亮绿色

def show_transaction_log():  # 定义show_transaction_log函数，用于展示交易记录
    display_title("交易记录")  # 调用display_title函数，打印标题"交易记录"
    with open("d:\\TransactionLog.txt", "r") as log:  # 打开文件TransactionLog.txt，以只读模式
        for line in log:  # 遍历文件的每一行
            print(line.strip())  # 打印去掉换行符的每一行的内容

def generate_report():  # 定义generate_report函数，用于生成报告
    display_title("生成报告")  # 调用display_title函数，打印标题"生成报告"
    with open("d:\\Report.txt", "w") as report:  # 打开文件Report.txt，以写入模式
        report.write("药品销售报告\n")  # 写入报告标题
        report.write("药品编号 药品名称 购进数量 购进价格 出售药品数 出售价\n")  # 写入药品信息的标题
        for i in range(SIZE):  # 循环SIZE次，遍历药品列表med
            if med[i]['num1'] != 0:  # 如果药品编号不为0，说明该药品有信息
                report.write(
                    f"{med[i]['num1']} {med[i]['name']} {med[i]['num2']} {med[i]['price1']} {med[i]['num3']} {med[i]['price2']}\n")  # 将药品信息写入报告文件
        report.write("\n交易记录\n")  # 写入交易记录的标题
        with open("d:\\TransactionLog.txt", "r") as log:  # 打开文件TransactionLog.txt，以只读模式
            for line in log:  # 遍历文件的每一行
                report.write(line)  # 将每一行的内容写入报告文件
    print(Fore.GREEN + "报告生成成功，保存在 d:\\Report.txt" + Style.RESET_ALL)  # 打印报告生成成功的提示信息，并设置字体为亮绿色

def validate_input(prompt, type_=None, min_=None, max_=None, range_=None):  # 定义validate_input函数，用于验证用户输入的值是否符合要求
    while True:  # 循环执行以下操作，直到用户输入符合要求的值
        ui = input(prompt)  # 提示用户输入值，并将输入结果赋值给变量ui
        if type_ is not None:  # 如果传入了type_参数（即要求输入的数据类型）
            try:
                ui = type_(ui)  # 将用户输入的字符串转换为指定类型的值
            except ValueError:  # 如果用户输入的字符串无法转换为指定类型的值
                print(Fore.RED + f"输入类型错误，请输入{type_.__name__}类型。" + Style.RESET_ALL)  # 打印输入类型错误的提示信息，并设置字体为红色
                continue  # 继续下一轮循环，重新提示用户输入
        if min_ is not None and ui < min_:  # 如果传入了min_参数（即要求输入的值不能小于min_）并且用户输入的值小于min_
            print(Fore.RED + f"输入值不能小于{min_}。" + Style.RESET_ALL)  # 打印输入值过小的提示信息，并设置字体为红色
            continue  # 继续下一轮循环，重新提示用户输入
        if max_ is not None and ui > max_:  # 如果传入了max_参数（即要求输入的值不能大于max_）并且用户输入的值大于max_
            print(Fore.RED + f"输入值不能大于{max_}。" + Style.RESET_ALL)  # 打印输入值过大的提示信息，并设置字体为红色
            continue  # 继续下一轮循环，重新提示用户输入
        if range_ is not None and ui not in range_:  # 如果传入了range_参数（即要求输入的值必须在range_范围内）并且用户输入的值不在range_范围内
            range_str = ", ".join(map(str, range_))  # 将range_范围内的值转换为字符串，并使用", "连接成一个新的字符串
            print(Fore.RED + f"输入值必须在以下范围内：{range_str}。" + Style.RESET_ALL)  # 打印输入值超出范围的提示信息，并设置字体为红色
            continue  # 继续下一轮循环，重新提示用户输入
        return ui  # 返回验证通过的值

def main():  # 定义main函数，作为程序的入口
    while True:  # 无限循环，直到用户选择退出
        display_menu()  # 调用display_menu函数，展示菜单选项

        choice = validate_input("请输入您的选择：", int, 1, 10)  # 提示用户输入选择，并进行输入验证
        if choice == 1:  # 如果选择为1
            save()  # 调用save函数，将药品信息保存到文件
        elif choice == 2:  # 如果选择为2
            chushou()  # 调用chushou函数，处理顾客买药
        elif choice == 3:  # 如果选择为3
            mednow()  # 调用mednow函数，查看药品信息
        elif choice == 4:  # 如果选择为4
            goujin()  # 调用goujin函数，购进药品
        elif choice == 5:  # 如果选择为5
            modify_medicine()  # 调用modify_medicine函数，修改药品信息
        elif choice == 6:  # 如果选择为6
            delete_medicine()  # 调用delete_medicine函数，删除药品信息
        elif choice == 7:  # 如果选择为7
            calculate_profit()  # 调用calculate_profit函数，计算利润
        elif choice == 8:  # 如果选择为8
            show_transaction_log()  # 调用show_transaction_log函数，展示交易记录
        elif choice == 9:  # 如果选择为9
            generate_report()  # 调用generate_report函数，生成报告
        elif choice == 10:  # 如果选择为10
            print(Fore.YELLOW + "系统退出，谢谢使用！" + Style.RESET_ALL)  # 打印系统退出的提示信息，并设置字体为黄色
            break  # 结束循环，退出程序
        else:
            print(Fore.RED + "无效的选择，请重试。" + Style.RESET_ALL)  # 打印无效的选择的提示信息，并设置字体为红色

if __name__ == "__main__":  # 如果当前脚本作为独立程序运行
    main()  # 调用main函数，启动程序的主逻辑